OstreeFetcher: provide proxy credentials if needed
authorJonathan Lebon <jlebon@redhat.com>
Fri, 14 Oct 2016 13:25:01 +0000 (09:25 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Fri, 14 Oct 2016 16:06:08 +0000 (16:06 +0000)
There seems to be an issue in libsoup which causes basic auth
credentials to not be passed to the proxy during requests. We thus have
to handle PROXY_UNAUTHORIZED responses and provide the auth ourselves.

Related: https://bugzilla.redhat.com/show_bug.cgi?id=1370558
Related: https://bugzilla.gnome.org/show_bug.cgi?id=772932

Closes: #529
Approved by: cgwalters

src/libostree/ostree-fetcher.c

index 3ddf2389f6c1e8e92ee2a7257a97c5930873bc1e..c2dc8ea467fbb6d3041196947d23396ebeb68cc9 100644 (file)
@@ -65,6 +65,9 @@ typedef struct {
 
   /* Also protected by output_stream_set_lock. */
   guint64 total_downloaded;
+
+  GError *oob_error;
+
 } ThreadClosure;
 
 static void
@@ -159,6 +162,8 @@ thread_closure_unref (ThreadClosure *thread_closure)
       g_clear_pointer (&thread_closure->output_stream_set, g_hash_table_unref);
       g_mutex_clear (&thread_closure->output_stream_set_lock);
 
+      g_clear_pointer (&thread_closure->oob_error, g_error_free);
+
       g_slice_free (ThreadClosure, thread_closure);
     }
 }
@@ -276,6 +281,29 @@ session_thread_config_flags (ThreadClosure *thread_closure,
     }
 }
 
+static void
+on_authenticate (SoupSession *session, SoupMessage *msg, SoupAuth *auth,
+                 gboolean retrying, gpointer user_data)
+{
+  ThreadClosure *thread_closure = user_data;
+
+  if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED)
+    {
+      SoupURI *uri = NULL;
+      g_object_get (session, SOUP_SESSION_PROXY_URI, &uri, NULL);
+      if (retrying)
+        {
+          g_autofree char *s = soup_uri_to_string (uri, FALSE);
+          g_set_error (&thread_closure->oob_error,
+                       G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED,
+                       "Invalid username or password for proxy '%s'", s);
+        }
+      else
+        soup_auth_authenticate (auth, soup_uri_get_user (uri),
+                                      soup_uri_get_password (uri));
+    }
+}
+
 static void
 session_thread_set_proxy_cb (ThreadClosure *thread_closure,
                              gpointer data)
@@ -285,6 +313,17 @@ session_thread_set_proxy_cb (ThreadClosure *thread_closure,
   g_object_set (thread_closure->session,
                 SOUP_SESSION_PROXY_URI,
                 proxy_uri, NULL);
+
+  /* libsoup won't necessarily pass any embedded username and password to proxy
+   * requests, so we have to be ready to handle 407 and handle them ourselves.
+   * See also: https://bugzilla.gnome.org/show_bug.cgi?id=772932
+   * */
+  if (soup_uri_get_user (proxy_uri) &&
+      soup_uri_get_password (proxy_uri))
+    {
+      g_signal_connect (thread_closure->session, "authenticate",
+                        G_CALLBACK (on_authenticate), thread_closure);
+    }
 }
 
 #ifdef HAVE_LIBSOUP_CLIENT_CERTS
@@ -998,10 +1037,23 @@ on_request_sent (GObject        *object,
                   code = G_IO_ERROR_FAILED;
                 }
 
-              local_error = g_error_new (G_IO_ERROR, code,
-                                         "Server returned status %u: %s",
-                                         msg->status_code,
-                                         soup_status_get_phrase (msg->status_code));
+              {
+                g_autofree char *errmsg =
+                  g_strdup_printf ("Server returned status %u: %s",
+                                   msg->status_code,
+                                   soup_status_get_phrase (msg->status_code));
+
+                /* Let's make OOB errors be the final one since they're probably
+                 * the cause for the error here. */
+                if (pending->thread_closure->oob_error)
+                  {
+                    local_error =
+                      g_error_copy (pending->thread_closure->oob_error);
+                    g_prefix_error (&local_error, "%s: ", errmsg);
+                  }
+                else
+                  local_error = g_error_new_literal (G_IO_ERROR, code, errmsg);
+              }
 
               if (pending->mirrorlist->len > 1)
                 g_prefix_error (&local_error,